#include <stdio.h>
#include <sys/types.h> 
#include <sys/ipc.h> 
#include <sys/msg.h> 
#include<string.h>
#include<pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <semaphore.h>
#include <unistd.h>
#include <sqlite3.h>
#include <sys/ioctl.h>
#include <sys/shm.h>
#include "./sem.h"
#include "./led_irq.h"
#include "./wind.h"
#include "./sound.h"
#define PATHNAME "/etc"
#define MSSIZE (sizeof(msg_t)-sizeof(long))
#define DATALEN 500
#define STAFF_DATABASE "data.db"
#define GET_TMP _IOR('t',0,int)
#define GET_HUM _IOR('t',1,int)
sqlite3 *db;
int msqid;
char* waddr;
int shmid,semid;
int ledfd1,windfd,soundfd,i2cfd,ledfd2,ledfd3;
int tem_up,tem_down;
int hum_up,hum_down;
int illu_up,illu_down;

/*定义消息结构*/
typedef struct msgbuf { 
	long mtype; /* message type, must be > 0 */ 
	char mtext[1024]; /* message data */ 
	char name[20];
	char passwd[20];
	int tem_up;
    int tem_down;
	int hum_up;
	int hum_down;
	int illu_up;
	int illu_down;
}msg_t;
msg_t msg;

typedef struct wabuff{
	int tem;
	int hum;	
}wab_t;
wab_t wab;
/*消息类型*/
int msg_typ[4] = {1,2,3,4};

/*定义信号量*/
sem_t main_sem; 	//主线程
sem_t login_sem; 	//登录线程
sem_t env_view_sem; //查看环境线程
sem_t env_set_sem; 	//设置环境线程
sem_t dev_ctrl_sem; //控制设备线程
/*
void *main_thread(){


}
*/

/*登录线程*/
void *login_thread(){
	char sql[DATALEN] = {0};
	char **result;
	char *errmsg;
	int nrow,ncolumn;
	while(1){ 
		sem_wait(&login_sem); 
		printf("登录线程被激活，有用户要登录\n");
		printf("%s\n",msg.name);
		printf("%s\n",msg.passwd);
		printf("%s\n",msg.mtext);
		sprintf(sql,"select * from userinfo where username='%s' and passwd='%s';",msg.name,msg.passwd);
		printf("[%s]\n",sql);
		if(sqlite3_get_table(db,sql,&result,&nrow,&ncolumn,NULL) != SQLITE_OK){
			printf("---****----%s.\n",sqlite3_errmsg(db));	

		}else{
			if(nrow == 0){

				msg.mtype = 11;
				memset(msg.mtext,0,sizeof(msg.mtext));
				strcpy(msg.mtext,"NO");
				if(-1 == msgsnd(msqid,&msg,MSSIZE,0)){
					perror("msgsend error.\n");
				}
			}else{

				msg.mtype = 11;
				// memset(msg.mtext,0,sizeof(msg.mtext));
				strcpy(msg.mtext,"OK");
				if(-1 == msgsnd(msqid,&msg,sizeof(msg_t)-sizeof(long),0)){
					printf("msqid = %d\n",msqid);
					printf("%s\n",msg.name);
					printf("%s\n",msg.passwd);
					printf("%s\n",msg.mtext);
					printf("%ld\n",msg.mtype);
					perror("msgsend error.\n");
				}
			}
		}
		sleep(1); 
		
		sem_post(&main_sem); 
	}

}

/*查看信息线程*/
void *env_view_thread(){

	while(1){ 
		sem_wait(&env_view_sem); 
		printf("查看环境线程被激活，提供仓库环境数据\n"); 
		//将共享内存映射到用户空间
		waddr = shmat(shmid,NULL,0);
		if(waddr == (void *)-1){
			perror("shmat error");
		}

		if(-1 == ioctl(i2cfd,GET_TMP,&wab.tem)){
			perror("ioctl tmp error");
		}
		if(-1 == ioctl(i2cfd,GET_HUM,&wab.hum)){
			perror("ioctl hum error");
		}
		P(semid,0);
		// 写操作
		memcpy(waddr,&wab,sizeof(wab));
		V(semid,1);

		sleep(1); 
		sem_post(&main_sem); 
	}

}
		
/*设置阈值线程*/
void *env_set_thread(){
	
	while(1){ 
		sem_wait(&env_set_sem); 
		printf("设置环境阈值线程被激活，为阈值变量赋值\n"); 
		tem_up = msg.tem_up;
		tem_down = msg.tem_down;
		hum_up = msg.hum_up;
		hum_down = msg.hum_down;
	    illu_up = msg.illu_up;	
		illu_down = msg.illu_down; 																																						
		sleep(1); 
		sem_post(&main_sem); 
	}

}

/*设备控制线程*/
void *dev_ctrl_thread(){
	while(1){ 
		sem_wait(&dev_ctrl_sem); 
		printf("控制设备线程被激活，将控制信息写入设备文件\n"); 
		if(!strcmp(msg.mtext,"led1_on")){
			if(-1 == ioctl(ledfd1,LED1_ON)){
				perror("ioctl led on error");
			}
		}else if(!strcmp(msg.mtext,"led1_off")){
			if(-1 == ioctl(ledfd1,LED1_OFF)){
				perror("ioctl led off error");
			}
		}	
		if(!strcmp(msg.mtext,"led2_on")){
			if(-1 == ioctl(ledfd2,LED2_ON)){
				perror("ioctl led on error");
			}
		}else if(!strcmp(msg.mtext,"led2_off")){
			if(-1 == ioctl(ledfd2,LED2_OFF)){
				perror("ioctl led off error");
			}
		}
		if(!strcmp(msg.mtext,"led3_on")){
			if(-1 == ioctl(ledfd3,LED3_ON)){
				perror("ioctl led on error");
			}
		}else if(!strcmp(msg.mtext,"led3_off")){
			if(-1 == ioctl(ledfd3,LED3_OFF)){
				perror("ioctl led off error");
			}
		}
		if(!strcmp(msg.mtext,"wind_on")){
			if(-1 == ioctl(windfd,WIND_ON)){
				perror("ioctl wind_on error");
			}
		}else if(!strcmp(msg.mtext,"wind_off")){
			if(-1 == ioctl(windfd,WIND_OFF)){
				perror("ioctl wind_off error");
			}
		}

		if(!strcmp(msg.mtext,"sound_on")){
			if(-1 == ioctl(soundfd,SOUND_ON)){
				perror("ioctl sound_on error");
			}
		}else if(!strcmp(msg.mtext,"sound_off")){
			if(-1 == ioctl(soundfd,SOUND_OFF)){
				perror("ioctl sound_off error");
			}
		}

		sleep(1); 
		sem_post(&main_sem); 
	}
}

int main(int argc, const char *argv[])
{
	char *errmsg;
	int down_hum,down_tem,down_illu;
	//打开数据库
	if(sqlite3_open(STAFF_DATABASE,&db) != SQLITE_OK){
		printf("%s\n",sqlite3_errmsg(db));
		sqlite3_free(errmsg);
	}else{
		printf("the database open success.\n");
	}
	//执行建表语句
	if(sqlite3_exec(db,"create table if not exists userinfo(username text PRIMARY KEY,passwd text)",NULL,NULL,&errmsg)!=SQLITE_OK){
		printf("%s.\n",errmsg);
        sqlite3_free(errmsg);
	}else{
		printf("create userinfo table success.\n");
	}

	
	pthread_t tid; 
	
	sem_init(&main_sem,0,1);//初始化信号量 
	sem_init(&login_sem,0,0);
	sem_init(&env_view_sem,0,0);//初始化信号量 
	sem_init(&env_set_sem,0,0);
	sem_init(&dev_ctrl_sem,0,0);

	//信号灯集的初始化
    semid =my_sem_init(2);
    if(semid == -1){
        printf("sem init error");
        return -1;
    }

	int ret ,i=0;
	if((ret = pthread_create(&tid,NULL,login_thread,NULL)) < 0 ){ 
		fprintf(stderr,"pthread_create = %s\n",strerror(ret)); 
		return -1; 
	}
	if((ret = pthread_create(&tid,NULL,env_view_thread,NULL)) < 0 ){ 
		fprintf(stderr,"pthread_create = %s\n",strerror(ret)); 
		return -1; 
	}
	if((ret = pthread_create(&tid,NULL,env_set_thread,NULL)) < 0 ){ 
		fprintf(stderr,"pthread_create = %s\n",strerror(ret)); 
		return -1; 
	}
	if((ret = pthread_create(&tid,NULL,dev_ctrl_thread,NULL)) < 0 ){ 
		fprintf(stderr,"pthread_create = %s\n",strerror(ret)); 
		return -1; 
	}
	
	key_t key = 0;
	key_t skey = 0;

	if((key = ftok(PATHNAME,'a')) == -1) 
	{ 
		perror("ftok");
		return -1; 
	}
	if((skey = ftok(PATHNAME,'s')) == -1){
		perror("ftoks");
		return -1; 
	}

	//创建消息队列 
	msqid = msgget(key,IPC_CREAT|0666); 
	if(msqid == -1) { 
		perror("msgget"); 
		return -1; 
	}
	//创建共享内存
	shmid = shmget(skey,4096,IPC_CREAT | 0666);
	if(-1 == shmid){
		perror("shmget error");
		return -1;
	}
	

	if(-1 == (ledfd1 = open("/dev/led1",O_RDWR))){
		perror("open dev/led1 error");
		return -1;
	}
	if(-1 == (ledfd2 = open("/dev/led2",O_RDWR))){
		perror("open dev/led2 error");
		return -1;
	}
	if(-1 == (ledfd3 = open("/dev/led3",O_RDWR))){
		perror("open dev/led3 error");
		return -1;
	}
	if(-1 == (windfd = open("/dev/wind",O_RDWR))){
		perror("open dev/wind error");
		return -1;
	}
	if(-1 == (soundfd = open("/dev/sound",O_RDWR))){
		perror("open dev/sound error");
		return -1;
	}
	if(-1 == (i2cfd = open("/dev/i2c",O_RDWR))){
		perror("open error ");
		return -1;
	}

	while(1) { 
		sem_wait(&main_sem);
		printf("msqid---- = %d\n",msqid);
		ret = msgrcv(msqid,&msg,sizeof(msg_t)-sizeof(long),msg_typ[i],IPC_NOWAIT);
		if(-1!=ret){
			switch(msg_typ[i]){
			case 1:
				sem_post(&login_sem);
				printf("接受到的消息为%s\n",msg.name);
				break;
			case 2:
				sem_post(&env_view_sem);
				printf("接受到的消息为%s\n",msg.mtext);
				break;
			case 3:
				sem_post(&env_set_sem);
				printf("接受到的消息为%s\n",msg.mtext);
				break;
			case 4:
				sem_post(&dev_ctrl_sem);
				printf("接受到的消息为%s\n",msg.mtext);
				break;
			default :
				break;

			}
		}

 
		printf("执行主线程，根据设置的阈值维护仓库环境\n");

		i++;
		if(i==4){
			i=0;
		}
		printf("tem_up=%d ,tem_down=%d , hum_up=%d,  hum_down=%d\n",tem_up,tem_down,hum_up,hum_down);
		if(-1 == ioctl(i2cfd,GET_TMP,&down_tem)){
			perror("ioctl tmp error");
		}
		if(-1 == ioctl(i2cfd,GET_HUM,&down_hum)){
			perror("ioctl hum error");
		}
		down_tem =175.72* down_tem /65536-46.85;
		down_hum =125* down_hum /65536-6;
		//温度
		if(down_tem > tem_up){
			if(-1 == ioctl(windfd,WIND_ON)){
				perror("ioctl wind_on error");
			}
		}else{
			if(-1 == ioctl(windfd,WIND_OFF)){
				perror("ioctl wind_off error");
			}
		}
		//湿度
		if(down_hum > hum_up){
			if(-1 == ioctl(ledfd2,LED2_ON)){
				perror("ioctl led on error");
			}
		}else if(down_hum < hum_down){
			if(-1 == ioctl(ledfd3,LED3_ON)){
				perror("ioctl led on error");
			}
		}else if(down_hum <= hum_up && down_hum >= hum_down){
			if(-1 == ioctl(ledfd2,LED2_OFF)){
				perror("ioctl led on error");
			}
			if(-1 == ioctl(ledfd3,LED3_OFF)){
				perror("ioctl led on error");
			}
		}

		printf("down_tem=%d ,down_hum=%d\n",down_tem,down_hum);
		sleep(1);
		sem_post(&main_sem);

	}
	// 取消地址映射
    if (shmdt(waddr))
    {
		perror("shmdt error");
		return -1;
	}

    // 删除共享内存
    if (shmctl(shmid, IPC_RMID, NULL))
	{
		perror("shctl error");
		return -1;
	}
    // 删除信号量
    sem_del(semid);
	return 0;
}
